package com.andreamerla.petslife.manager;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import com.andreamerla.petslife.PetsLifeApplication;
import com.andreamerla.petslife.model.PlaceDetails;
import com.andreamerla.petslife.model.PlaceList;
import com.andreamerla.petslife.util.Utils;
import com.google.api.client.http.*;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.jackson2.JacksonFactory;

import java.util.Locale;

/**
 * Created by IntelliJ IDEA.
 * User: a.merla
 * Date: 19/07/13
 * Time: 11.50
 */
public class GooglePlacesManager {
    /**
     * Documentation: https://developers.google.com/places/documentation/search
     */

    private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

    // Google Places search URLs
    private static final String PLACES_SEARCH_URL = "https://maps.googleapis.com/maps/api/place/search/json?";
    private static final String PLACES_TEXT_SEARCH_URL = "https://maps.googleapis.com/maps/api/place/search/json?";
    private static final String PLACES_DETAILS_URL = "https://maps.googleapis.com/maps/api/place/details/json?";

    // Google API Key
//    private static String API_KEY = "AIzaSyCRLa4LQZWNQBcjCYcIVYA45i9i8zfClqc"; // Taken from an online tutorial
    private static String API_KEY = "AIzaSyD32nJxC3vPsueSh69iY6ZIp-ssD4r1O08";

    public static PlaceList nearbySearch(double latitude, double longitude, int radius, String types, boolean rankByDistance) throws Exception {
        try {
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching nearby places...  Coord: (" + latitude + "," + longitude + ") - Radius: " + radius + "m - Types: " + types + " - Rank by distance: " + rankByDistance);

            HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
            HttpRequest request = httpRequestFactory.buildGetRequest(new GenericUrl(PLACES_SEARCH_URL));
            request.getUrl().put("key", getApiKey());
            request.getUrl().put("language", Locale.getDefault().getLanguage());
            request.getUrl().put("location", latitude + "," + longitude);
            if (rankByDistance)
                request.getUrl().put("rankby", "distance");
            else
                request.getUrl().put("radius", radius);
            request.getUrl().put("sensor", "false");
            if (types != null)
                request.getUrl().put("types", types);
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching nearby places...  URL: " + request.getUrl().toString());

            PlaceList list = request.execute().parseAs(PlaceList.class);
            Log.d("Places Status", "" + list.status);
            return list;
        } catch (HttpResponseException e) {
            Log.e("Error:", e.getMessage());
            return null;
        }
    }

    public static PlaceList textSearch(String query, double latitude, double longitude, int radius, String types) throws Exception {
        try {
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching places by text...  Query: " + query + " - Coord: (" + latitude + "," + longitude + ") - Radius: " + radius + "m - Types: " + types);

            HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
            HttpRequest request = httpRequestFactory.buildGetRequest(new GenericUrl(PLACES_SEARCH_URL));
            request.getUrl().put("key", getApiKey());
            request.getUrl().put("language", Locale.getDefault().getLanguage());
            request.getUrl().put("query", query);
            request.getUrl().put("location", latitude + "," + longitude);
            request.getUrl().put("radius", radius);
            request.getUrl().put("sensor", "false");
            if (types != null)
                request.getUrl().put("types", types);
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching places by text...  URL: " + request.getUrl().toString());

            PlaceList list = request.execute().parseAs(PlaceList.class);
            Log.d("Places Status", "" + list.status);
            return list;
        } catch (HttpResponseException e) {
            Log.e("Error:", e.getMessage());
            return null;
        }
    }

    public static PlaceDetails placeDetails(String reference) throws Exception {
        try {
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching place details...  Reference: " + reference);

            HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
            HttpRequest request = httpRequestFactory.buildGetRequest(new GenericUrl(PLACES_DETAILS_URL));
            request.getUrl().put("key", getApiKey());
            request.getUrl().put("language", Locale.getDefault().getLanguage());
            request.getUrl().put("reference", reference);
            request.getUrl().put("sensor", "false");
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Searching place details...  URL: " + request.getUrl().toString());

            PlaceDetails place = request.execute().parseAs(PlaceDetails.class);
            return place;
        } catch (HttpResponseException e) {
            Log.e("Error in Perform Details", e.getMessage());
            throw e;
        }
    }

    public static PlaceList nextPage(String pagetoken) throws Exception {
        try {
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Requesting next page places...  Next page token: " + pagetoken);

            HttpRequestFactory httpRequestFactory = createRequestFactory(HTTP_TRANSPORT);
            HttpRequest request = httpRequestFactory.buildGetRequest(new GenericUrl(PLACES_SEARCH_URL));
            request.getUrl().put("key", getApiKey());
            request.getUrl().put("pagetoken", pagetoken);
            Log.d(Utils.getLogTag(GooglePlacesManager.class), "Requesting next page places...  URL: " + request.getUrl().toString());

            PlaceList list = request.execute().parseAs(PlaceList.class);
            Log.d("Places Status", "" + list.status);
            return list;
        } catch (HttpResponseException e) {
            Log.e("Error:", e.getMessage());
            return null;
        }
    }

    private static HttpRequestFactory createRequestFactory(final HttpTransport transport) {
        return transport.createRequestFactory(new HttpRequestInitializer() {
            public void initialize(HttpRequest request) {
                HttpHeaders headers = new HttpHeaders();
                headers.setUserAgent("Searching Places..");
                request.setHeaders(headers);
                JsonObjectParser parser = new JsonObjectParser(new JacksonFactory());
                request.setParser(parser);
            }
        });
    }

    private static String getApiKey() {
        if (API_KEY == null)
            API_KEY = getApiKeyFromMetaData();
        return API_KEY;
    }

    private static String getApiKeyFromMetaData() {
        try {
            PetsLifeApplication appContext = PetsLifeApplication.getAppContext();
            ApplicationInfo ai = appContext.getPackageManager().getApplicationInfo(appContext.getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;
            return bundle.getString("com.google.android.maps.v2.API_KEY");
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(Utils.getLogTag(GooglePlacesManager.class), "Failed to load meta-data, NameNotFound: " + e.getMessage());
        } catch (NullPointerException e) {
            Log.e(Utils.getLogTag(GooglePlacesManager.class), "Failed to load meta-data, NullPointer: " + e.getMessage());
        }
        return null;
    }
}
